#include "wrapping_integers.hh"

// Dummy implementation of a 32-bit wrapping integer

// For Lab 2, please replace with a real implementation that passes the
// automated checks run by `make check_lab2`.

template <typename... Targs>
void DUMMY_CODE(Targs &&... /* unused */) {}

using namespace std;

//! Transform an "absolute" 64-bit sequence number (zero-indexed) into a WrappingInt32
//! \param n The input absolute 64-bit sequence number
//! \param isn The initial sequence number
WrappingInt32 wrap(uint64_t n, WrappingInt32 isn) {
    return WrappingInt32{static_cast<uint32_t>(n) + isn.raw_value()};
}

//! Transform a WrappingInt32 into an "absolute" 64-bit sequence number (zero-indexed)
//! \param n The relative sequence number
//! \param isn The initial sequence number
//! \param checkpoint A recent absolute 64-bit sequence number
//! \returns the 64-bit sequence number that wraps to `n` and is closest to `checkpoint`
//!
//! \note Each of the two streams of the TCP connection has its own ISN. One stream
//! runs from the local TCPSender to the remote TCPReceiver and has one ISN,
//! and the other stream runs from the remote TCPSender to the local TCPReceiver and
//! has a different ISN.
uint64_t unwrap(WrappingInt32 n, WrappingInt32 isn, uint64_t checkpoint) {
    uint64_t i = 0ul;
    uint64_t abs_seq = 0ul;
    uint64_t u64_n = static_cast<uint64_t>(n.raw_value());
    uint64_t u64_isn = static_cast<uint64_t>(isn.raw_value());
	
    // checkpoint in [0, 2^32 -1], n abs in this range also ?
    // but when n < isn is special
    if (u64_n >= checkpoint && checkpoint < (1ul << 32)) {
	if (n.raw_value() >= isn.raw_value()) {
		abs_seq = u64_n - u64_isn;
	} else {
		abs_seq = (1ul << 32) + u64_n - u64_isn;
	}
    } else {
	i = (checkpoint >> 32) + 2;
    	do {
		abs_seq = u64_n + (i << 32) - u64_isn;
		i--;
    	} while ( (abs_seq > checkpoint ? (abs_seq - checkpoint) : (checkpoint - abs_seq)) > static_cast<uint64_t>((1ul << 31) - 1));
    }
	
    return abs_seq;
}
